package memoryallocationrecycling

import (
	"fmt"
	"math/rand"
	"time"
)

// 定义空闲区结构体
type FreeArea struct {
	// 空闲区开始地址
	StartAddress int
	// 空闲区大小
	Size int
	// 空闲区状态，0为不可用，1为可用
	Status int
}

// 变量
var (
	FreeBlock  []FreeArea
	FreeareNum int
)

// 创建空闲区，初始化变量
func Create(num int) {
	FreeareNum = num
	FreeBlock = make([]FreeArea, num)
	rand.Seed(time.Now().UnixMilli())
	for i := 0; i < num; i++ {
		freeArea := &FreeArea{
			StartAddress: rand.Intn(200),
			Size:         rand.Intn(100),
			Status:       rand.Intn(2),
		}
		FreeBlock[i] = *freeArea
	}
}

// 分配内存方法，输入大小
func Alloc(applyArea int) (result int) {
	flag := 0
	for i := 0; i < FreeareNum; i++ {
		// 如果空闲区状态为可用状态并且空闲区大小大于需求
		if FreeBlock[i].Status == 1 && FreeBlock[i].Size > applyArea {
			FreeBlock[i].StartAddress += applyArea
			FreeBlock[i].Size -= applyArea
			flag = 1
			result = FreeBlock[i].StartAddress - applyArea
		} else if FreeBlock[i].Status == 1 && FreeBlock[i].Size == applyArea {
			// 如果空闲区状态为可用状态并且空闲区大小等于需求
			// 更改空闲区状态为不可用
			FreeBlock[i].Status = 0
			flag = 1
			result = FreeBlock[i].StartAddress
		}
	}
	if flag == 0 {
		result = -1
	}
	return result
}

// 回收内存方法
func RecoveryFree(startAddress int, size int) {
	// flag1代表释放区的高地址是否邻接一个空闲区
	// flag2代表释放区的高低地址是否都邻接一个空闲区
	// flag3代表释放区的低地址是否邻接一个空闲区

	flag1, flag2, flag3 := 0, 0, 0
	for i := 0; i < FreeareNum; i++ {
		if FreeBlock[i].StartAddress == startAddress+1 && FreeBlock[i].Status == 1 {
			size += FreeBlock[i].Size
			flag1 = 1
			for j := 0; j < FreeareNum; j++ {
				if FreeBlock[j].StartAddress+FreeBlock[j].Size == startAddress && FreeBlock[j].Status == 1 {
					FreeBlock[i].Status = 0
					FreeBlock[j].Size += 1
					flag2 = 1
					break
				}
			}
			if flag2 == 0 {
				FreeBlock[i].StartAddress = startAddress
				FreeBlock[i].Size = size
				break
			}
		}
	}
	if flag1 == 0 {
		for i := 0; i < FreeareNum; i++ {
			if FreeBlock[i].StartAddress+FreeBlock[i].Size == startAddress && FreeBlock[i].Status == 1 {
				FreeBlock[i].Size += 1
				flag3 = 1
				break
			}
		}
		if flag3 == 0 {
			for i := 0; i < FreeareNum; i++ {
				if FreeBlock[i].Status == 0 {
					FreeBlock[i].StartAddress = startAddress
					FreeBlock[i].Size = size
					FreeBlock[i].Status = 1
					break
				}
			}
		}
	}
}

// 交换空闲区方法
func Adjust() {
	mid := &FreeArea{}
	for i := 0; i < FreeareNum-1; i++ {
		for j := 0; j < FreeareNum-i-1; j++ {
			// 如果当前空闲区地址大于下一个空闲区地址，交换
			if FreeBlock[j].StartAddress > FreeBlock[j+1].StartAddress {
				mid.StartAddress = FreeBlock[j].StartAddress
				mid.Size = FreeBlock[j].Size
				mid.Status = FreeBlock[j].Status
				FreeBlock[j].StartAddress = FreeBlock[j+1].StartAddress
				FreeBlock[j].Size = FreeBlock[j+1].Size
				FreeBlock[j].Status = FreeBlock[j+1].Status
				FreeBlock[j+1].StartAddress = mid.StartAddress
				FreeBlock[j+1].Size = mid.Size
				FreeBlock[j+1].Status = mid.Status
			}
			// 如果当前空闲区状态等于0并且下一个空闲区状态为1，交换
			if FreeBlock[j].Status == 0 && FreeBlock[j+1].Status == 1 {
				mid.StartAddress = FreeBlock[j].StartAddress
				mid.Size = FreeBlock[j].Size
				mid.Status = FreeBlock[j].Status
				FreeBlock[j].StartAddress = FreeBlock[j+1].StartAddress
				FreeBlock[j].Size = FreeBlock[j+1].Size
				FreeBlock[j].Status = FreeBlock[j+1].Status
				FreeBlock[j+1].StartAddress = mid.StartAddress
				FreeBlock[j+1].Size = mid.Size
				FreeBlock[j+1].Status = mid.Status
			}
		}
	}
}

// 显示空闲区信息
func ShowFreeArea() {
	fmt.Println("空闲区列表：")
	for i := 0; i < FreeareNum; i++ {
		fmt.Printf("开始地址：%v \t大小：%v \t状态：%v\t\n", FreeBlock[i].StartAddress, FreeBlock[i].Size, FreeBlock[i].Status)
	}
	fmt.Println()
}
